/* * Copyright (C) 2015 BigTesting.org * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.bigtesting.fixd.tests; import static org.junit.Assert.*; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import org.bigtesting.fixd.Method; import org.bigtesting.fixd.ServerFixture; import org.bigtesting.fixd.capture.CapturedRequest; import org.bigtesting.fixd.marshalling.Marshaller; import org.bigtesting.fixd.marshalling.Unmarshaller; import org.bigtesting.fixd.request.HttpRequest; import org.bigtesting.fixd.request.HttpRequestHandler; import org.bigtesting.fixd.response.HttpResponse; import org.bigtesting.fixd.session.PathParamSessionHandler; import org.bigtesting.fixd.session.RequestParamSessionHandler; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.fasterxml.jackson.databind.ObjectMapper; import com.gargoylesoftware.htmlunit.HttpMethod; import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.WebRequest; import com.ning.http.client.AsyncCompletionHandler; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.HttpResponseBodyPart; import com.ning.http.client.ListenableFuture; import com.ning.http.client.Response; import com.ning.http.multipart.StringPart; /** * * @author Luis Antunes */ public class TestServerFixture { private ServerFixture server; @Before public void beforeEachTest() throws Exception { /* * Instantiate the server fixture before each test. * It could also have been initialized as part of the * server field declaration above, as JUnit will * instantiate this Test class for each of its tests. */ server = new ServerFixture(8080); server.start(); } @Test public void testSimpleGet() throws Exception { server.handle(Method.GET, "/") .with(200, "text/plain", "Hello"); /* * we're using the ning.com AsyncHttpClient, check it out: * https://github.com/AsyncHttpClient/async-http-client */ Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/") .execute() .get(); assertEquals("Hello", resp.getResponseBody().trim()); } @Test public void testSimpleGetWithPathParam() throws Exception { server.handle(Method.GET, "/name/:name") .with(200, "text/plain", "Hello :name"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/name/Tim") .execute() .get(); assertEquals("Hello Tim", resp.getResponseBody().trim()); } @Test public void testSimpleGetWithRegexPathParam() throws Exception { server.handle(Method.GET, "/name/:name<[A-Za-z]+>") .with(200, "text/plain", "Hello :name"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/name/Tim") .execute() .get(); assertEquals("Hello Tim", resp.getResponseBody().trim()); resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/name/123") .execute() .get(); assertEquals(404, resp.getStatusCode()); } @Test public void testSimplePutWithRequestBody() throws Exception { server.handle(Method.PUT, "/name") .with(200, "text/plain", "Hello [request.body]"); Response resp = new AsyncHttpClient() .preparePut("http://localhost:8080/name") .setBody("Tim") .execute() .get(); assertEquals("Hello Tim", resp.getResponseBody().trim()); } @Test public void testSimpleGetWithRequestMethod() throws Exception { server.handle(Method.GET, "/say-method") .with(200, "text/plain", "Value: [request.method]"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/say-method") .execute() .get(); assertEquals("Value: GET", resp.getResponseBody().trim()); } @Test public void testSimpleGetWithRequestPath() throws Exception { server.handle(Method.GET, "/say-path") .with(200, "text/plain", "Value: [request.path]"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/say-path") .execute() .get(); assertEquals("Value: /say-path", resp.getResponseBody().trim()); } @Test public void testSimpleGetWithRequestQuery() throws Exception { server.handle(Method.GET, "/say-query") .with(200, "text/plain", "Value: [request.query]"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/say-query?a=b") .execute() .get(); assertEquals("Value: a=b", resp.getResponseBody().trim()); } @Test public void testSimpleGetWithRequestTime() throws Exception { server.handle(Method.GET, "/say-time") .with(200, "text/plain", "Value: [request.time]"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/say-time") .execute() .get(); assertTrue(resp.getResponseBody().trim().matches("Value: [0-9]*")); } @Test public void testSimpleGetWithRequestMajor() throws Exception { server.handle(Method.GET, "/say-major") .with(200, "text/plain", "Value: [request.major]"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/say-major") .execute() .get(); assertEquals("Value: 1", resp.getResponseBody().trim()); } @Test public void testSimpleGetWithRequestMinor() throws Exception { server.handle(Method.GET, "/say-minor") .with(200, "text/plain", "Value: [request.minor]"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/say-minor") .execute() .get(); assertEquals("Value: 1", resp.getResponseBody().trim()); } @Test public void testSimpleGetWithRequestTarget() throws Exception { server.handle(Method.GET, "/say-target") .with(200, "text/plain", "Value: [request.target]"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/say-target") .execute() .get(); assertEquals("Value: /say-target", resp.getResponseBody().trim()); } @Test public void testSimpleGetWithRequestParameter() throws Exception { server.handle(Method.GET, "/greeting") .with(200, "text/plain", "Hello [request?name]"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/greeting?name=Tim") .execute() .get(); assertEquals("Hello Tim", resp.getResponseBody().trim()); } @Test public void testSimplePostWithRequestParameter() throws Exception { server.handle(Method.POST, "/greeting", "application/x-www-form-urlencoded") .with(200, "text/plain", "Hello [request?name]"); Response resp = new AsyncHttpClient() .preparePost("http://localhost:8080/greeting") .addParameter("name", "Tim") .execute() .get(); assertEquals("Hello Tim", resp.getResponseBody().trim()); } @Test public void testSimpleGetWithRequestHeader() throws Exception { server.handle(Method.GET, "/say-user-agent") .with(200, "text/plain", "Value: [request$User-Agent]"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/say-user-agent") .execute() .get(); assertEquals("Value: NING/1.0", resp.getResponseBody().trim()); } @Test public void testSimpleGetWithSplatParam() throws Exception { server.handle(Method.GET, "/name/*") .with(200, "text/plain", "Hello *[0]"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/name/Tim") .execute() .get(); assertEquals("Hello Tim", resp.getResponseBody().trim()); } @Test public void testStatefulRequests() throws Exception { server.handle(Method.PUT, "/name/:name") .with(200, "text/plain", "OK") .withSessionHandler(new PathParamSessionHandler()); server.handle(Method.GET, "/name") .with(200, "text/plain", "Name: {name}"); WebClient client = new WebClient(); Page page = client.getPage(new WebRequest(new URL( "http://localhost:8080/name/Tim"), HttpMethod.PUT)); assertEquals(200, page.getWebResponse().getStatusCode()); page = client.getPage(new WebRequest(new URL( "http://localhost:8080/name"), HttpMethod.GET)); assertEquals("Name: Tim", page.getWebResponse().getContentAsString().trim()); } @Test public void testStatefulRequestsUsingRequestParams() throws Exception { server.handle(Method.POST, "/", "application/x-www-form-urlencoded") .with(200, "text/plain", "OK") .withSessionHandler(new RequestParamSessionHandler()); server.handle(Method.GET, "/") .with(200, "text/plain", "Name: {name}"); WebClient client = new WebClient(); Page page = client.getPage(new WebRequest(new URL( "http://localhost:8080/?name=Tim"), HttpMethod.POST)); assertEquals(200, page.getWebResponse().getStatusCode()); page = client.getPage(new WebRequest(new URL( "http://localhost:8080/"), HttpMethod.GET)); assertEquals("Name: Tim", page.getWebResponse().getContentAsString().trim()); } @Test public void testInvalidatingSessionMakesSessionInvalid() throws Exception { server.handle(Method.PUT, "/name/:name") .with(200, "text/plain", "OK") .withSessionHandler(new PathParamSessionHandler()); server.handle(Method.GET, "/say-hello") .with(200, "text/plain", "Hello {name}"); server.handle(Method.GET, "/clear") .with(new HttpRequestHandler() { public void handle(HttpRequest request, HttpResponse response) { request.getSession().invalidate(); response.setStatusCode(200); response.setContentType("text/plain"); response.setBody("OK"); } }); WebClient client = new WebClient(); Page page = client.getPage(new WebRequest(new URL( "http://localhost:8080/name/John"), HttpMethod.PUT)); assertEquals(200, page.getWebResponse().getStatusCode()); page = client.getPage(new WebRequest(new URL( "http://localhost:8080/say-hello"), HttpMethod.GET)); assertEquals("Hello John", page.getWebResponse().getContentAsString().trim()); page = client.getPage(new WebRequest(new URL( "http://localhost:8080/clear"), HttpMethod.GET)); assertEquals(200, page.getWebResponse().getStatusCode()); page = client.getPage(new WebRequest(new URL( "http://localhost:8080/say-hello"), HttpMethod.GET)); assertEquals("Hello {name}", page.getWebResponse().getContentAsString().trim()); } @Test public void testDelay() throws Exception { server.handle(Method.GET, "/suspend") .with(200, "text/plain", "OK") .after(100, TimeUnit.SECONDS); try { new AsyncHttpClient() .prepareGet("http://localhost:8080/suspend") .execute() .get(1, TimeUnit.SECONDS); fail("request should have timed out after 1 second"); } catch (Exception e) {} } @Test public void testEvery() throws Exception { server.handle(Method.GET, "/echo/:message") .with(200, "text/plain", "message: :message") .every(200, TimeUnit.MILLISECONDS, 2); final List<String> chunks = new ArrayList<String>(); ListenableFuture<Integer> f = new AsyncHttpClient() .prepareGet("http://localhost:8080/echo/hello") .execute(new AddToListOnBodyPartReceivedHandler(chunks)); assertEquals(200, (int)f.get()); assertEquals("[message: hello, message: hello]", chunks.toString()); } @Test public void testUpon() throws Exception { server.handle(Method.GET, "/subscribe") .with(200, "text/plain", "message: :message") .upon(Method.GET, "/broadcast/:message"); final List<String> broadcasts = new ArrayList<String>(); ListenableFuture<Integer> f = new AsyncHttpClient() .prepareGet("http://localhost:8080/subscribe") .execute(new AddToListOnBodyPartReceivedHandler(broadcasts)); /* need some time for the above request to complete * before the broadcast requests can start */ Thread.sleep(200); for (int i = 0; i < 2; i++) { new AsyncHttpClient() .prepareGet("http://localhost:8080/broadcast/hello" + i) .execute().get(); /* sometimes the last broadcast request is not * finished before f.done() is called */ Thread.sleep(200); } f.done(null); assertEquals("[message: hello0, message: hello1]", broadcasts.toString()); } @Test public void testUponwithNoSubscribers() throws Exception { server.handle(Method.GET, "/subscribe") .with(200, "text/plain", "message: :message") .upon(Method.GET, "/broadcast/:message"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/broadcast/hello") .execute() .get(); assertEquals(200, resp.getStatusCode()); assertEquals("", resp.getResponseBody().trim()); } @Test public void testUponUsingRequestBody() throws Exception { server.handle(Method.GET, "/subscribe") .with(200, "text/plain", "message: [request.body]") .upon(Method.PUT, "/broadcast"); final List<String> broadcasts = new ArrayList<String>(); ListenableFuture<Integer> f = new AsyncHttpClient() .prepareGet("http://localhost:8080/subscribe") .execute(new AddToListOnBodyPartReceivedHandler(broadcasts)); /* need some time for the above request to complete * before the broadcast requests can start */ Thread.sleep(200); for (int i = 0; i < 2; i++) { new AsyncHttpClient() .preparePut("http://localhost:8080/broadcast") .setBody("hello" + i) .execute().get(); /* sometimes the last broadcast request is not * finished before f.done() is called */ Thread.sleep(200); } f.done(null); assertEquals("[message: hello0, message: hello1]", broadcasts.toString()); } @Test public void testUponRemovesSubscriberWhenSubscribingClientDisconnects() throws Exception { server.handle(Method.GET, "/subscribe") .with(200, "text/plain", "message: [request.body]") .upon(Method.PUT, "/broadcast"); final List<String> broadcasts = new ArrayList<String>(); AsyncHttpClient subscribingClient = new AsyncHttpClient(); ListenableFuture<Integer> f = subscribingClient .prepareGet("http://localhost:8080/subscribe") .execute(new AddToListOnBodyPartReceivedHandler(broadcasts)); /* need some time for the above request to complete * before the broadcast requests can start */ Thread.sleep(200); new AsyncHttpClient() .preparePut("http://localhost:8080/broadcast") .setBody("hello1") .execute().get(); /* sometimes the last broadcast request is not * finished before f.done() is called */ Thread.sleep(200); f.done(null); subscribingClient.close(); new AsyncHttpClient() .preparePut("http://localhost:8080/broadcast") .setBody("hello2") .execute().get(); /* allow some time for the last broadcast to be processed * before going on to the assertions */ Thread.sleep(200); assertEquals("[message: hello1]", broadcasts.toString()); assertEquals(3, server.capturedRequests().size()); CapturedRequest firstRequest = server.request(); assertNotNull(firstRequest); assertEquals("GET /subscribe HTTP/1.1", firstRequest.getRequestLine()); CapturedRequest secondRequest = server.request(); assertNotNull(secondRequest); assertEquals("PUT /broadcast HTTP/1.1", secondRequest.getRequestLine()); assertTrue(secondRequest.isBroadcast()); /* * the second /broadcast request should not be broadcast because * the subscriber should have been removed when the subscribing * client disconnected */ CapturedRequest thirdRequest = server.request(); assertNotNull(thirdRequest); assertEquals("PUT /broadcast HTTP/1.1", thirdRequest.getRequestLine()); assertFalse(thirdRequest.isBroadcast()); } @Test public void testUponWithRequestHandler() throws Exception { server.handle(Method.GET, "/subscribe") .with(new HttpRequestHandler() { public void handle(HttpRequest request, HttpResponse response) { response.setStatusCode(200); response.setContentType("text/plain"); response.setBody("message: " + request.getBody()); } }) .upon(Method.PUT, "/broadcast"); final List<String> broadcasts = new ArrayList<String>(); ListenableFuture<Integer> f = new AsyncHttpClient() .prepareGet("http://localhost:8080/subscribe") .execute(new AddToListOnBodyPartReceivedHandler(broadcasts)); /* need some time for the above request to complete * before the broadcast requests can start */ Thread.sleep(100); for (int i = 0; i < 2; i++) { new AsyncHttpClient() .preparePut("http://localhost:8080/broadcast") .setBody("hello" + i) .execute().get(); /* sometimes the last broadcast request is not * finished before f.done() is called */ Thread.sleep(200); } f.done(null); assertEquals("[message: hello0, message: hello1]", broadcasts.toString()); } @Test public void testUponAndMarshallingAndUnmarshallingWithHandler() throws Exception { server.marshal("application/json") .with(new JSONMarshaller()); server.unmarshal("application/json") .with(new JSONUnmarshaller()); server.handle(Method.GET, "/subscribe") .with(new HttpRequestHandler() { public void handle(HttpRequest request, HttpResponse response) { response.setStatusCode(200); response.setContentType("application/json"); SimplePojo entity = request.getBody(SimplePojo.class); response.setBody(new SimplePojo(entity.getVal())); } }) .upon(Method.PUT, "/broadcast", "application/json"); final List<String> broadcasts = new ArrayList<String>(); ListenableFuture<Integer> f = new AsyncHttpClient() .prepareGet("http://localhost:8080/subscribe") .execute(new AddToListOnBodyPartReceivedHandler(broadcasts)); /* need some time for the above request to complete * before the broadcast requests can start */ Thread.sleep(100); for (int i = 0; i < 2; i++) { new AsyncHttpClient() .preparePut("http://localhost:8080/broadcast") .setHeader("Content-Type", "application/json") .setBody("{\"val\":\"hello" + i + "\"}") .execute().get(); /* sometimes the last broadcast request is not * finished before f.done() is called */ Thread.sleep(200); } f.done(null); assertEquals("[{\"val\":\"hello0\"}, {\"val\":\"hello1\"}]", broadcasts.toString()); } @Test public void testUponAndMarshallingWithoutHandler() throws Exception { server.marshal("application/json") .with(new JSONMarshaller()); server.handle(Method.GET, "/subscribe") .with(200, "application/json", new SimplePojo("marshalledJSON")) .upon(Method.PUT, "/broadcast"); final List<String> broadcasts = new ArrayList<String>(); AsyncHttpClient subscribingClient = new AsyncHttpClient(); ListenableFuture<Integer> f = subscribingClient .prepareGet("http://localhost:8080/subscribe") .execute(new AddToListOnBodyPartReceivedHandler(broadcasts)); /* need some time for the above request to complete * before the broadcast requests can start */ Thread.sleep(100); for (int i = 0; i < 2; i++) { new AsyncHttpClient() .preparePut("http://localhost:8080/broadcast") .execute().get(); /* sometimes the last broadcast request is not * finished before f.done() is called */ Thread.sleep(200); } f.done(null); assertEquals("[{\"val\":\"marshalledJSON\"}, {\"val\":\"marshalledJSON\"}]", broadcasts.toString()); } @Test public void testUponWithMultipleScubscribers() throws Exception { server.handle(Method.GET, "/subscribe") .with(200, "text/plain", "message: :message") .upon(Method.GET, "/broadcast/:message"); final List<String> client1Broadcasts = new ArrayList<String>(); ListenableFuture<Integer> f1 = new AsyncHttpClient() .prepareGet("http://localhost:8080/subscribe") .execute(new AddToListOnBodyPartReceivedHandler(client1Broadcasts)); final List<String> client2Broadcasts = new ArrayList<String>(); ListenableFuture<Integer> f2 = new AsyncHttpClient() .prepareGet("http://localhost:8080/subscribe") .execute(new AddToListOnBodyPartReceivedHandler(client2Broadcasts)); /* need some time for the above requests to complete * before the broadcast requests can start */ Thread.sleep(200); for (int i = 0; i < 2; i++) { new AsyncHttpClient() .prepareGet("http://localhost:8080/broadcast/hello" + i) .execute().get(); /* sometimes the last broadcast request is not * finished before f.done() is called */ Thread.sleep(200); } f1.done(null); f2.done(null); assertEquals("[message: hello0, message: hello1]", client1Broadcasts.toString()); assertEquals("[message: hello0, message: hello1]", client2Broadcasts.toString()); } @Test public void testUponWithTimeout() throws Exception { server.handle(Method.GET, "/subscribe") .with(200, "text/plain", "message: :message") .upon(Method.GET, "/broadcast/:message") .withTimeout(100, TimeUnit.MILLISECONDS); ListenableFuture<Response> f = new AsyncHttpClient() .prepareGet("http://localhost:8080/subscribe") .execute(); /* * If the process didn't timeout, the subscribe request * would wait indefinitely, as no broadcast requests * are being made. */ assertEquals(408, f.get().getStatusCode()); } @Test public void testUponHandlesDifferentSubscriptions() throws Exception { server.handle(Method.GET, "/subscr1") .with(200, "text/plain", "message1") .upon(Method.GET, "/broadc1"); server.handle(Method.GET, "/subscr2") .with(200, "text/plain", "message2") .upon(Method.GET, "/broadc2"); final List<String> broadcasts1 = new ArrayList<String>(); ListenableFuture<Integer> f1 = new AsyncHttpClient() .prepareGet("http://localhost:8080/subscr1") .execute(new AddToListOnBodyPartReceivedHandler(broadcasts1)); final List<String> broadcasts2 = new ArrayList<String>(); ListenableFuture<Integer> f2 = new AsyncHttpClient() .prepareGet("http://localhost:8080/subscr2") .execute(new AddToListOnBodyPartReceivedHandler(broadcasts2)); /* need some time for the above request to complete * before the broadcast requests can start */ Thread.sleep(200); new AsyncHttpClient() .prepareGet("http://localhost:8080/broadc2") .execute().get(); /* sometimes the last broadcast request is not * finished before f.done() is called */ Thread.sleep(200); f1.done(null); f2.done(null); assertEquals("[]", broadcasts1.toString()); assertEquals("[message2]", broadcasts2.toString()); } @Test public void recordsRequests() throws Exception { server.handle(Method.GET, "/say-hello") .with(200, "text/plain", "Hello!"); server.handle(Method.PUT, "/name/:name") .with(200, "text/plain", "OK"); assertEquals(0, server.capturedRequests().size()); new AsyncHttpClient() .prepareGet("http://localhost:8080/say-hello") .execute().get(); new AsyncHttpClient() .preparePut("http://localhost:8080/name/Tim") .execute().get(); assertEquals(2, server.capturedRequests().size()); CapturedRequest firstRequest = server.request(); assertNotNull(firstRequest); assertEquals("GET /say-hello HTTP/1.1", firstRequest.getRequestLine()); CapturedRequest secondRequest = server.request(); assertNotNull(secondRequest); assertEquals("PUT /name/Tim HTTP/1.1", secondRequest.getRequestLine()); } @Test public void recordsRequestsOnSameURL() throws Exception { server.handle(Method.GET, "/say-hello/:name") .with(200, "text/plain", "Hello :name!"); assertEquals(0, server.capturedRequests().size()); new AsyncHttpClient() .prepareGet("http://localhost:8080/say-hello/John") .execute().get(); new AsyncHttpClient() .prepareGet("http://localhost:8080/say-hello/Tim") .execute().get(); assertEquals(2, server.capturedRequests().size()); CapturedRequest firstRequest = server.request(); assertNotNull(firstRequest); assertEquals("GET /say-hello/John HTTP/1.1", firstRequest.getRequestLine()); CapturedRequest secondRequest = server.request(); assertNotNull(secondRequest); assertEquals("GET /say-hello/Tim HTTP/1.1", secondRequest.getRequestLine()); } @Test public void addsHeader() throws Exception { server.handle(Method.GET, "/") .with(302, "text/plain", "page moved") .withHeader("Location", "http://localhost:8080/new-location"); server.handle(Method.GET, "/new-location") .with(200, "text/plain", "OK"); new AsyncHttpClient() .prepareGet("http://localhost:8080/") .setFollowRedirects(true) .execute().get(); assertEquals(2, server.capturedRequests().size()); CapturedRequest firstRequest = server.request(); assertNotNull(firstRequest); assertEquals("GET / HTTP/1.1", firstRequest.getRequestLine()); CapturedRequest secondRequest = server.request(); assertNotNull(secondRequest); assertEquals("GET /new-location HTTP/1.1", secondRequest.getRequestLine()); } @Test public void testSimpleGetWithCustomHandlerReturnsStringBody() throws Exception { server.handle(Method.GET, "/name/:name") .with(new HttpRequestHandler() { public void handle(HttpRequest request, HttpResponse response) { response.setStatusCode(200); response.setContentType("text/plain"); response.setBody("Hello " + request.getPathParameter("name")); } }); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/name/Tim") .execute() .get(); assertEquals("Hello Tim", resp.getResponseBody().trim()); } @Test public void testSimpleGetWithCustomHandlerReturnsInterpolatedBody() throws Exception { server.handle(Method.GET, "/name/:name") .with(new HttpRequestHandler() { public void handle(HttpRequest request, HttpResponse response) { response.setStatusCode(200); response.setContentType("text/plain"); response.setInterpolatedBody("Hello :name"); } }); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/name/Tim") .execute() .get(); assertEquals("Hello Tim", resp.getResponseBody().trim()); } @Test public void testSimpleGetWithCustomHandlerReturnsByteArrayBody() throws Exception { server.handle(Method.GET, "/name") .with(new HttpRequestHandler() { public void handle(HttpRequest request, HttpResponse response) { response.setStatusCode(200); response.setContentType("text/plain"); response.setBody("Hello Tim".getBytes()); } }); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/name") .execute() .get(); assertEquals("Hello Tim", resp.getResponseBody().trim()); } @Test public void testSimpleGetWithCustomHandlerReturnsInputStreamBody() throws Exception { server.handle(Method.GET, "/name") .with(new HttpRequestHandler() { public void handle(HttpRequest request, HttpResponse response) { response.setStatusCode(200); response.setContentType("text/plain"); response.setBody(new ByteArrayInputStream("Hello Tim".getBytes())); } }); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/name") .execute() .get(); assertEquals("Hello Tim", resp.getResponseBody().trim()); } @Test public void testSettingMaxCapturedRequestsLimitsStoredCapturedRequests() throws Exception { server.handle(Method.GET, "/:id").with(200, "text/plain", ":id"); server.setMaxCapturedRequests(2); new AsyncHttpClient().prepareGet("http://localhost:8080/1").execute().get(); new AsyncHttpClient().prepareGet("http://localhost:8080/2").execute().get(); new AsyncHttpClient().prepareGet("http://localhost:8080/3").execute().get(); assertEquals(2, server.capturedRequests().size()); CapturedRequest captured = server.request(); assertEquals("GET /2 HTTP/1.1", captured.getRequestLine()); captured = server.request(); assertEquals("GET /3 HTTP/1.1", captured.getRequestLine()); } @Test public void testDifferentContentTypesAreHandledDifferently() throws Exception { server.handle(Method.GET, "/resource", "text/plain") .with(200, "text/plain", "Received text/plain content"); server.handle(Method.GET, "/resource", "application/json") .with(200, "text/plain", "Received application/json content"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/resource") .setHeader("Content-Type", "text/plain") .execute().get(); assertEquals("Received text/plain content", resp.getResponseBody().trim()); resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/resource") .setHeader("Content-Type", "application/json") .execute().get(); assertEquals("Received application/json content", resp.getResponseBody().trim()); } @Test public void testMultipartContentTypeIsSupported() throws Exception { server.handle(Method.POST, "/resource", "multipart/form-data") .with(200, "text/palin", "Success!"); Response resp = new AsyncHttpClient() .preparePost("http://localhost:8080/resource") .addBodyPart(new StringPart("name", "value")) .execute() .get(); assertEquals("Success!", resp.getResponseBody().trim()); } @Test public void testSplatPathParameterForAllRequests() throws Exception { server.handle(Method.GET, "/*") .with(200, "text/plain", "[request.path]"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/1") .execute().get(); assertEquals("/1", resp.getResponseBody().trim()); resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/2") .execute().get(); assertEquals("/2", resp.getResponseBody().trim()); } @Test public void testSplatPathParameterWithPrecedingResource() throws Exception { server.handle(Method.GET, "/protected/*") .with(200, "text/plain", "[request.path]"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/hello") .execute().get(); assertEquals(404, resp.getStatusCode()); resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/protected/content") .execute().get(); assertEquals("/protected/content", resp.getResponseBody().trim()); } @Test public void testSplatPathParameterInterjectedBetweenResources() throws Exception { server.handle(Method.GET, "/protected/*/content") .with(200, "text/plain", "[request.path]"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/hello") .execute().get(); assertEquals(404, resp.getStatusCode()); resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/protected/1/content") .execute().get(); assertEquals("/protected/1/content", resp.getResponseBody().trim()); resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/protected/blah/content") .execute().get(); assertEquals("/protected/blah/content", resp.getResponseBody().trim()); resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/protected/1/blah/content") .execute().get(); assertEquals(404, resp.getStatusCode()); } @Test public void testSplatPathParametersOccurringMultipleTimes() throws Exception { server.handle(Method.GET, "/say/*/to/*") .with(200, "text/plain", "[request.path]"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/hello") .execute().get(); assertEquals(404, resp.getStatusCode()); resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/say/hello/to/world") .execute().get(); assertEquals("/say/hello/to/world", resp.getResponseBody().trim()); resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/say/bye/to/Tim") .execute().get(); assertEquals("/say/bye/to/Tim", resp.getResponseBody().trim()); } @Test public void testSplatPathParamsWithVariousPathParams() throws Exception { server.handle(Method.GET, "/say/*/to/:name/:times<[0-9]+>/*") .with(200, "text/plain", "[request.path] :name :times"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/hello") .execute().get(); assertEquals(404, resp.getStatusCode()); resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/say/hello/to/John") .execute().get(); assertEquals(404, resp.getStatusCode()); resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/say/hello/to/John/1/") .execute().get(); assertEquals("/say/hello/to/John/1/ John 1", resp.getResponseBody().trim()); resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/say/hello/to/Tim/1/time") .execute().get(); assertEquals("/say/hello/to/Tim/1/time Tim 1", resp.getResponseBody().trim()); } @Test public void testMarshalling() throws Exception { server.marshal("application/json") .with(new JSONMarshaller()); server.handle(Method.GET, "/marshal") .with(200, "application/json", new SimplePojo("marshalledJSON")); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/marshal") .execute().get(); assertEquals("{\"val\":\"marshalledJSON\"}", resp.getResponseBody().trim()); } @Test public void testMarshallingWithHandler() throws Exception { server.marshal("application/json") .with(new JSONMarshaller()); server.handle(Method.GET, "/marshal") .with(new HttpRequestHandler() { public void handle(HttpRequest request, HttpResponse response) { response.setStatusCode(200); response.setContentType("application/json"); response.setBody(new SimplePojo("marshalledJSON")); } }); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/marshal") .execute().get(); assertEquals("{\"val\":\"marshalledJSON\"}", resp.getResponseBody().trim()); } @Test public void testUnmarshalling() throws Exception { server.unmarshal("application/json") .with(new JSONUnmarshaller()); server.handle(Method.PUT, "/unmarshal", "application/json") .with(new HttpRequestHandler() { public void handle(HttpRequest request, HttpResponse response) { response.setStatusCode(200); response.setContentType("text/plain"); SimplePojo entity = request.getBody(SimplePojo.class); response.setBody(entity != null ? entity.getVal() : "error"); } }); Response resp = new AsyncHttpClient() .preparePut("http://localhost:8080/unmarshal") .setHeader("Content-Type", "application/json") .setBody("{\"val\":\"unmarshalledJSON\"}") .execute().get(); assertEquals("unmarshalledJSON", resp.getResponseBody().trim()); } @Test public void testMarshallingAndUnmarshallingWithHandler() throws Exception { server.marshal("application/json") .with(new JSONMarshaller()); server.unmarshal("application/json") .with(new JSONUnmarshaller()); server.handle(Method.PUT, "/marshal-and-unmarshal", "application/json") .with(new HttpRequestHandler() { public void handle(HttpRequest request, HttpResponse response) { response.setStatusCode(200); response.setContentType("application/json"); SimplePojo entity = request.getBody(SimplePojo.class); response.setBody(new SimplePojo(entity.getVal())); } }); Response resp = new AsyncHttpClient() .preparePut("http://localhost:8080/marshal-and-unmarshal") .setHeader("Content-Type", "application/json") .setBody("{\"val\":\"someJSON\"}") .execute().get(); assertEquals("{\"val\":\"someJSON\"}", resp.getResponseBody().trim()); } @Test public void redirects() throws Exception { server.handle(Method.GET, "/") .withRedirect("http://localhost:8080/new-location"); server.handle(Method.GET, "/new-location") .with(200, "text/plain", "OK"); new AsyncHttpClient() .prepareGet("http://localhost:8080/") .setFollowRedirects(true) .execute().get(); assertEquals(2, server.capturedRequests().size()); CapturedRequest firstRequest = server.request(); assertNotNull(firstRequest); assertEquals("GET / HTTP/1.1", firstRequest.getRequestLine()); CapturedRequest secondRequest = server.request(); assertNotNull(secondRequest); assertEquals("GET /new-location HTTP/1.1", secondRequest.getRequestLine()); } @Test public void redirectWithoutStatusCodeHasCorrectDefaultStatusCode() throws Exception { server.handle(Method.GET, "/") .withRedirect("http://localhost:8080/new-location"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/") .setFollowRedirects(false) .execute().get(); assertEquals(302, resp.getStatusCode()); assertEquals("http://localhost:8080/new-location", resp.getHeader("Location")); } @Test public void redirectsWithStatusCode() throws Exception { server.handle(Method.GET, "/") .withRedirect("http://localhost:8080/new-location", 301); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/") .setFollowRedirects(false) .execute().get(); assertEquals(301, resp.getStatusCode()); assertEquals("http://localhost:8080/new-location", resp.getHeader("Location")); } @Test public void testCustomHandlerRedirects() throws Exception { server.handle(Method.GET, "/") .with(new HttpRequestHandler() { public void handle(HttpRequest request, HttpResponse response) { response.redirect("http://localhost:8080/new-location"); } }); server.handle(Method.GET, "/new-location") .with(200, "text/plain", "OK"); new AsyncHttpClient() .prepareGet("http://localhost:8080/") .setFollowRedirects(true) .execute().get(); assertEquals(2, server.capturedRequests().size()); CapturedRequest firstRequest = server.request(); assertNotNull(firstRequest); assertEquals("GET / HTTP/1.1", firstRequest.getRequestLine()); CapturedRequest secondRequest = server.request(); assertNotNull(secondRequest); assertEquals("GET /new-location HTTP/1.1", secondRequest.getRequestLine()); } @Test public void testCustomHandlerRedirectsWithStatusCode() throws Exception { server.handle(Method.GET, "/") .with(new HttpRequestHandler() { public void handle(HttpRequest request, HttpResponse response) { response.redirect("http://localhost:8080/new-location", 301); } }); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/") .setFollowRedirects(false) .execute().get(); assertEquals(301, resp.getStatusCode()); assertEquals("http://localhost:8080/new-location", resp.getHeader("Location")); } @Test public void testHandlesEncodedPaths() throws Exception { server.handle(Method.GET, "/foo+bar") .with(200, "text/plain", "ok"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/foo%2Bbar") .execute().get(); assertEquals("ok", resp.getResponseBody().trim()); } @Test public void testHandlesEncodedPathSeparators() throws Exception { server.handle(Method.GET, "/foo/bar") .with(200, "text/plain", "ok"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/foo%2Fbar") .execute().get(); assertEquals(404, resp.getStatusCode()); } @Test public void testHandlesEncodedPathSeparatorsWithNamedParams() throws Exception { server.handle(Method.GET, "/:name") .with(200, "text/plain", ":name"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/foo%2Fbar") .execute().get(); assertEquals("foo/bar", resp.getResponseBody().trim()); } @Test public void testHandlesEncodedPlusWithNamedParams() throws Exception { server.handle(Method.GET, "/:name") .with(200, "text/plain", ":name"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/foo%2Bbar") .execute().get(); assertEquals("foo+bar", resp.getResponseBody().trim()); } @Test public void testHandlesUnencodedPlusWithNamedParams() throws Exception { server.handle(Method.GET, "/:name") .with(200, "text/plain", ":name"); Response resp = new AsyncHttpClient() .prepareGet("http://localhost:8080/foo+bar") .execute().get(); assertEquals("foo+bar", resp.getResponseBody().trim()); } @Test public void testGetPort() { assertEquals(8080, server.getPort()); } @Test public void testGetPortAfterPortChosenAutomatically() throws Exception { ServerFixture fixture = new ServerFixture(); fixture.start(); try { assertTrue(fixture.getPort() >= 1); } finally { fixture.stop(); } } @Test public void testSimpleRequestAfterPortChosenAutomatically() throws Exception { ServerFixture fixture = new ServerFixture(); fixture.start(); fixture.handle(Method.GET, "/") .with(200, "text/plain", "Hello"); try { Response resp = new AsyncHttpClient() .prepareGet("http://localhost:" + fixture.getPort() + "/") .execute().get(); assertEquals("Hello", resp.getResponseBody().trim()); } finally { fixture.stop(); } } @After public void afterEachTest() throws Exception { server.stop(); } /*--------------------------------------------*/ private class AddToListOnBodyPartReceivedHandler extends AsyncCompletionHandler<Integer> { private final List<String> chunks; public AddToListOnBodyPartReceivedHandler(List<String> chunks) { this.chunks = chunks; } public Integer onCompleted(Response r) throws Exception { return r.getStatusCode(); } public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { String chunk = new String(bodyPart.getBodyPartBytes()).trim(); if (chunk.length() != 0) { chunks.add(chunk); } return STATE.CONTINUE; } } private static final ObjectMapper mapper = new ObjectMapper(); public static class JSONMarshaller implements Marshaller { public InputStream marshal(Object entity) { try { String payload = mapper.writeValueAsString(entity); return new ByteArrayInputStream(payload.getBytes()); } catch (Exception e) { throw new RuntimeException("could not marshal", e); } } } public static class JSONUnmarshaller implements Unmarshaller { public <T> T unmarshal(InputStream in, Class<T> type) { try { return mapper.readValue(in, type); } catch (Exception e) { throw new RuntimeException("could not unmarshal", e); } } } public static class SimplePojo { private String val; public SimplePojo() {} public SimplePojo(String val) { this.val = val; } public String getVal() { return val; } public void setVal(String val) { this.val = val; } @Override public String toString() { return val; } } }